package com.example.dormitory;

import com.example.base.entity.*;
import com.example.base.exception.GlobalException;
import com.example.base.rabbitmq.MQSender;
import com.example.base.rabbitmq.OrderMessage;
import com.example.base.service.DormitoryService;
import com.example.base.service.OrderService;
import com.example.base.service.UserService;
import com.example.base.utils.JsonUtil;
import com.example.base.vo.RespBean;
import com.example.base.vo.RespBeanEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.util.*;

@Slf4j
@Controller
@RequestMapping("/dorm")
public class DormitoryController implements InitializingBean {

    @Autowired
    private DormitoryService dormitoryService;

    @Autowired
    private UserService userService;

    @Autowired
    private OrderService orderService;

    @GetMapping("/list")
    @ResponseBody
    public RespBean getAllDormitory() {
        Map<Object, Object> allDormitory = dormitoryService.getAllDormitory();
        return RespBean.success(allDormitory);
    }

    private Boolean checkInfoMatch(UserInfo info, String code) {
        String userCode = userService.getUserCodeByUid(info.getId());
        return userCode.equals(code);
    }

    private Boolean checkIsChoosed(UserInfo info) {
        UserDormRelation relation = userService.getRelationByUid(info.getStudentNo());
        return relation != null && relation.getValid();
    }

    @Autowired
    private MQSender mqSender;
    private static final Object lock = new Object();

    private RespBean checkUserData(String submitterId, String submitterCode,
                                   List<String> studentNo, List<String> code,
                                   List<UserInfo> validUserList) {
        List<String> studentNos = new ArrayList<>(), codes = new ArrayList<>();
        studentNos.add(submitterId);
        codes.add(submitterCode);
        studentNos.addAll(studentNo);
        codes.addAll(code);

        String gender = "";
        for (int i = 0; i < studentNos.size(); ++i) {
            if (StringUtils.isEmpty(studentNos.get(i))) continue;
            UserInfo info = userService.getUserInfoByStudentNo(studentNos.get(i));
            if (info == null) {
                RespBean respBean = RespBean.error(RespBeanEnum.STUDENTNO_ERROR);
                respBean.setMsg("学号：" + studentNos.get(i) + "错误");
                return respBean;
            }
            if (!checkInfoMatch(info, codes.get(i))) {
                RespBean respBean = RespBean.error(RespBeanEnum.MATCH_ERROR);
                respBean.setMsg(info.getStudentNo() + "与认证码" + codes.get(i) + "不匹配");
                return respBean;
            }
            if (i == 0) gender = info.getGender();
            else if (!info.getGender().equals(gender)) {
                throw new GlobalException(RespBeanEnum.GENDER_ERROR);
            }
            if (checkIsChoosed(info)) {
                RespBean respBean = RespBean.error(RespBeanEnum.CHOOSE_ERROR);
                respBean.setMsg(info.getStudentNo() + "已经选过宿舍");
                return respBean;
            }
            validUserList.add(info);
        }
        return RespBean.success();
    }

    private String getRoomInfo(Room room) {
        Integer unitId = dormitoryService.getUnitIdByRoomId(room.getId());
        Unit unit = dormitoryService.getUnitById(unitId);
        Building building = dormitoryService.getBuildingById(unit.getBuildingId());
        System.out.println("building = " + building);
        return building.getName() + " " + unit.getName() + " " + room.getName();
    }

    /**
     * 用户轮询选宿舍结果
     *
     * @param studentNo
     * @return 排队中0, 成功1，失败-1
     */
    @PostMapping("/result")
    @ResponseBody
    public RespBean getResult(String studentNo) {
        System.out.println("studentNo = " + studentNo);
        Integer result = dormitoryService.getResult(studentNo);
        System.out.println("result = " + result);
        Map<Object, Object> ret = new HashMap<>();
        if (result > 0) {
            Room room = dormitoryService.getRoomById(result);
            ret.put("msg", getRoomInfo(room));
        }
        ret.put("status", result);
        return RespBean.success(ret);
    }

    @PostMapping("/choose")
    @ResponseBody
    public RespBean parseUserOrder(@RequestBody FormData formData) {
        List<String> studentNo = formData.getStudentNos();
        List<String> code = formData.getCodes();
        String submitterId = formData.getSubmitterId();
        String submitterCode = formData.getSubmitterCode();
        String buildingName = formData.getBuildingName();
        if (!StringUtils.isEmpty(submitterCode) && !StringUtils.isEmpty(submitterId)) {
            ArrayList<UserInfo> validUserList = new ArrayList<>();
            RespBean respBean = checkUserData(submitterId, submitterCode, studentNo, code, validUserList);
            if (respBean.getCode() != 200) {
                //信息校验失败，不生成订单
                return respBean;
            }
            log.info("信息校验通过");
            Integer buildingId = dormitoryService.getIdByBuildingName(buildingName);
            if (buildingId == null) {
                throw new GlobalException(RespBeanEnum.BUILDING_ERROR);
            }
            List<Integer> units = dormitoryService.getUnitsByBuildingId(buildingId);
            if (units == null || units.size() == 0) {
                throw new GlobalException(RespBeanEnum.BUILDING_NO_UNIT_ERROR);
            }
            Integer count = validUserList.size();
            String gender = validUserList.get(0).getGender();
            List<Room> rooms = new ArrayList<>();
            for (Integer unit : units) {
                rooms.addAll(dormitoryService.getRoomsByUnitIdAndGenderGreaterThanCount(unit, count, gender));
            }
            if (rooms.size() == 0) {
                return RespBean.error(RespBeanEnum.NOROOM_ERROR);
            }

            log.info("validUserList = " + validUserList);

            Random random = new Random();
            int index = random.nextInt(rooms.size());
            Room target = rooms.get(index);
            // redis预减操作 如何保证原子性??
            synchronized (lock) {
                target.setRemain(target.getRemain() - count);
                dormitoryService.cacheRoom(target);
            }

            //生成订单信息
            Order order = new Order();
            order.setSubmitterId(validUserList.get(0).getId());
            order.setBuildingId(buildingId);
            order.setCount(count);
            order.setGender(gender);
            order.setSuccess(true);

            //放入消息队列异步处理
            OrderMessage orderMessage = new OrderMessage(order, validUserList, target);
            mqSender.sendOrder(JsonUtil.object2JsonStr(orderMessage));
            return RespBean.success(0);
        } else {
            throw new GlobalException(RespBeanEnum.SUBMITTER_EMPTY_ERROR);
        }
    }

    /**
     * 系统初始化，把building，unit，room表加载到redis中
     *
     * @throws Exception
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        List<Building> buildings = dormitoryService.getAllBuilding();
        if (!CollectionUtils.isEmpty(buildings)) {
            buildings.forEach(building -> dormitoryService.cacheBuilding(building));
        }
        List<Unit> units = dormitoryService.getAllUnits();
        if (!CollectionUtils.isEmpty(units)) {
            units.forEach(unit -> dormitoryService.cacheUnit(unit));
        }
        List<Room> rooms = dormitoryService.getAllRooms();
        if (!CollectionUtils.isEmpty(rooms)) {
            rooms.forEach(room -> dormitoryService.cacheRoom(room));
        }
    }
}
